/**
 * @fileOverview
 * @author iNahoo
 * @since 2022/3/2.
 */

const parseCSV = require('csv-parser');
const { createReadStream } = require('fs');
const { resolve } = require('path');
const { createDupMapping, generateCSV, ATTR_ID_MAP } = require('./common');

const ORIGIN = resolve(__dirname, '../origin/大采集.csv');
const OUTPUT = resolve(__dirname, '../src/data/大采集_std.csv');
const MATERIAL_TABLE = resolve(__dirname, '../src/data/素材列表_std.csv');

const BLOCK_WIDTH = 5;
const WEATHER_ID_MAP = createDupMapping(['晴天', '下雨', '雪天', '打雷'], {
  ['下雪']: '雪天'
});
const TOOL_ID_MAP = createDupMapping(['镰刀', '捕虫网', '镐头', '钓鱼', '爆破锤', '弹弓'], {
  ['镐子']: '镐头'
});

const table = [];
const nativeBlocks = [];
const outputRows = [];
const materialNameMapping = {};

/**
 * 获取基本的二维表格
 * @return {Promise}
 */
async function getBaseTable() {
  return new Promise((r, j) => {
    createReadStream(ORIGIN).pipe(parseCSV({
      headers: false
    }))
      .on('data', (data) => {
        // 强行匹配 Array.from
        data.length = 24;
        const row = Array.from(data).map(v => v.trim());
        table.push(row);
      })
      .on('end', () => {
        r(table);
      })
      .on('error', err => {
        j(err);
      })
  });
}

async function getMaterialTable() {
  return new Promise((r, j) => {
    createReadStream(MATERIAL_TABLE).pipe(parseCSV())
      .on('data', (data) => {
        materialNameMapping[data['素材名']] = data;
      })
      .on('end', () => {
        r(table);
      })
      .on('error', err => {
        j(err);
      })
  });
}

/**
 * 整理行数据
 */
function splitBlocks() {

  // 分割原始区块
  table.forEach((row, rowIndex) => {
    if (row[0].match(/^\d+$/)) {
      const areaId = Number(row[0]);
      row[0] = '';

      let mapId = 0;
      row.forEach((col, colIndex) => {
        if (col) {

          // 计算区块高度
          let h = 1;
          let content
          do {
            if (!table[rowIndex + h]) {
              break;
            }
            content = table[rowIndex + h][colIndex + 1];
            if (!content) {
              break;
            }
            h++;
          } while (true);

          // 添加区块
          nativeBlocks.push({
            areaId,
            mapId: areaId * 10 + mapId,
            mapName: col,

            r: rowIndex,
            c: colIndex - 2,
            h,
          });

          mapId++;
        }
      });
    }
  });

}

function analizeBlock() {
  nativeBlocks.forEach(nb => {
    const contentRows = table.slice(nb.r + 2, nb.r + nb.h).map(row => row.slice(nb.c, nb.c + BLOCK_WIDTH));

    let contextWeather = '';
    contentRows.forEach(row => {
      if (row[0]) contextWeather = row[0];

      const tool = row[1];

      row.slice(2).forEach((col, index) => {
        const material = materialNameMapping[col];
        outputRows.push({
          areaId: nb.areaId,
          mapId: nb.mapId,
          mapName: nb.mapName,

          star: index + 1,
          weather: contextWeather,
          weatherId: WEATHER_ID_MAP[contextWeather],
          tool,
          toolId: TOOL_ID_MAP[tool],
          materialName: col,

          material,
        });

        if (material === undefined) {
          throw new TypeError(`未知的素材:${col}`)
        }

        if (WEATHER_ID_MAP[contextWeather] === undefined) {
          throw new TypeError(`未知的天气:${contextWeather}`)
        }

        if (TOOL_ID_MAP[tool] === undefined) {
          throw new TypeError(`未知的工具:${tool}`)
        }
      })
    })
  });
}

// 排序
function sort() {
  const order = ['mapId', 'toolId', 'weatherId', 'star'];
  outputRows.sort((a, b) => {
    let ret = 0;
    order.some(key => {
      if (a[key] === b[key]) {
        return false;
      }

      ret = a[key] > b[key] ? 1 : -1;
      return true;
    });

    return ret;
  })
}

// 输出
function output() {
  generateCSV(
    [
      ['地图', 'mapName'],
      ['工具', 'tool'],
      ['天气', 'weather'],
      ['星数', 'star'],
      ['素材', 'materialName'],

      ['主属性', r => r.material['主属性']],
      ['类型', r => r.material['类型']],

      ['areaId'],
      ['mapId'],
      ['toolId'],
      ['weatherId'],
      ['mainAttrId', r => r.material.mainAttrId],
    ],
    outputRows,
    OUTPUT
  )
}

(async function main() {
  await getBaseTable();
  await getMaterialTable();
  splitBlocks();
  analizeBlock();
  sort();
  output();
})()
